﻿using System;
using System.IO;
using System.Net;
using System.Windows.Forms;
using System.Xml;
using NeoBackground.Properties;
using Wms.Client;

namespace NeoBackground
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            Settings.Default.PropertyChanged += DefaultPropertyChanged;

            InitializeComponent();
            notifyIcon1.Visible = true;
            notifyIcon1.Text = Resources.ProgramDescription;
            notifyIcon1.Icon = Resources.appicon;
            useBackground.Checked = Settings.Default.UseBaseMap;

            timer1.Interval = (int)Settings.Default.Period.TotalMilliseconds;
            timer1.Start();

            if (!Directory.Exists(TempPath))
                Directory.CreateDirectory(TempPath);

            if (!File.Exists(CapabilitiesFile))
                GetCapabilitiesFile();

            if(!File.Exists(BackgroundFile))
            {
                var server = new Server(CapabilitiesFile);
                GetMap(server, BackgroundLayerName);
            }

            SetupLayerMenu();

            //ApplySettings();

            Wallpaper.Set(BackgroundFile, m_currentImageTitle, Wallpaper.Style.Stretched);

            eventLog1.WriteEntry(Resources.StartedSuccessfullyMessage);
        }

        private void SetupLayerMenu()
        {
            var server = new Server(CapabilitiesFile);
            var caps = server.Capabilities;

            if (caps.Document != null)
            {
                var nodes = caps.Document.SelectNodes("//Layer[Name]");
                mapsToolStripMenuItem.DropDownItems.Clear();
                if (nodes != null)
                    if (nodes.Count > 0)
                    {
                        foreach(XmlNode node in nodes)
                        {
                            var newMenu = mapsToolStripMenuItem.DropDownItems.Add(node["Title"].InnerText);
                            newMenu.Tag = node;
                            newMenu.Click += LayerMenuClick;
                        }
                    }
            }
        }

        void LayerMenuClick(object sender, EventArgs e)
        {
            SpecificNewPicture((XmlNode)((ToolStripMenuItem)sender).Tag);
            
        }

        private const string SERVER = @"http://neowms.sci.gsfc.nasa.gov/wms/wms";
        private static readonly string BackgroundLayerName = Resources.BackgroundLayerName;

        private static readonly Random Randomizer = new Random();
        private static readonly string TempPath = Path.GetTempPath() + Application.ProductName + @"\";
        private static readonly string CapabilitiesFile =  TempPath + @"capabilities.xml";
        private static readonly string BackgroundFile = TempPath + BackgroundLayerName + ".png";
        private int m_currentLayerId;
        private string m_currentImageName;
        private string m_currentImageTitle;

        private static void GetCapabilitiesFile()
        {
            // Create a request to get the 
            // capabilities document from the server.
            var serverUri = new UriBuilder(SERVER);
            var capsRequest = new CapabilitiesRequestBuilder(serverUri.Uri);

            // Retrieve the capabilities document and cache it locally.
            var wr = WebRequest.Create(capsRequest.Uri);
            wr.Credentials = CredentialCache.DefaultCredentials;
            wr.Proxy.Credentials = CredentialCache.DefaultCredentials;
            //wr.UseDefaultCredentials = true;
            var response = wr.GetResponse();

            CopyStreamToFile(response.GetResponseStream(), CapabilitiesFile);           

            
        }

        private void notifyIcon1_MouseDoubleClick(object sender, MouseEventArgs e)
        {
            RandomNewPicture();
        }

        private static void CopyStreamToFile( Stream stream, string destination )
        {
            using (var bs = new BufferedStream(stream))
            {
                using (var os = File.OpenWrite(destination))
                {
                    var buffer = new byte[2 * 4096];
                    int nBytes;
                    while ((nBytes = bs.Read(buffer, 0, buffer.Length)) > 0)
                    {
                        os.Write(buffer, 0, nBytes);
                    }
                }
            }
        }

        private void GetMap(Server server, string currentImageName)
        {
            try
            {
                var caps = server.Capabilities;
                var mapRequest = new MapRequestBuilder(new Uri(caps.GetMapRequestUri))
                                     {
                                         Layers = currentImageName,
                                         Styles = "",
                                         Format = "image/png",
                                         Srs = "EPSG:4326",
                                         BoundingBox = "-180.0,-90.0,180.0,90.0",
                                         Height = 1200,
                                         Width = 1920,
                                         Transparent = true
                                     };

                // Retrieve the map and cache it locally.
                var mwr = WebRequest.Create(mapRequest.Uri);
                mwr.Credentials = CredentialCache.DefaultCredentials;
                mwr.Proxy.Credentials = CredentialCache.DefaultCredentials;
                var mresponse = mwr.GetResponse();

                CopyStreamToFile(mresponse.GetResponseStream(), MapFileName(currentImageName));
            }
            catch(Exception e)
            {
                eventLog1.WriteEntry(e.Message);
            }
        }

        private void GetLegend(XmlNode layerNode)
        {

            try
            {
                XmlNode uriNode = layerNode.SelectSingleNode("Style/LegendURL/OnlineResource/@*[local-name()='href']");
                if (uriNode != null)
                {
                    // Retrieve the map and cache it locally.
                    var mwr = WebRequest.Create(uriNode.InnerText);
                    mwr.Credentials = CredentialCache.DefaultCredentials;
                    mwr.Proxy.Credentials = CredentialCache.DefaultCredentials;
                    var mresponse = mwr.GetResponse();

                    CopyStreamToFile(mresponse.GetResponseStream(), MapFileName(Resources.LegendFileName));

                }
                else
                {
                    File.Delete(MapFileName(Resources.LegendFileName));
                }
            }
            catch (Exception e)
            {
                eventLog1.WriteEntry(e.Message);
            }

        }


        public static string MapFileName(string layerName)
        {
            return TempPath + layerName + @".png";
        }

        private void RandomNewPicture()
        {
            var server = new Server(CapabilitiesFile);
            var caps = server.Capabilities;

            if (caps.Document != null)
            {
                var nodes = caps.Document.SelectNodes("//Layer[Name]");

                if (nodes != null)
                    if (nodes.Count > 0)
                    {
                        m_currentLayerId = Randomizer.Next(nodes.Count);
                        // ReSharper disable PossibleNullReferenceException
                        m_currentImageName = nodes[m_currentLayerId]["Name"].InnerText;
                        m_currentImageTitle = nodes[m_currentLayerId]["Title"].InnerText;
                        // ReSharper restore PossibleNullReferenceException
                        GetMap(server, m_currentImageName);
                        GetLegend(nodes[m_currentLayerId]);
                        ApplySettings();

                    }
            }
            
        }

        private void SpecificNewPicture(XmlNode tag)
        {
            var server = new Server(CapabilitiesFile);
            var caps = server.Capabilities;

            if (caps.Document != null)
            {
                var nodes = caps.Document.SelectNodes("//Layer[Name]");

                if (nodes != null)
                    if (nodes.Count > 0)
                    {
                        m_currentLayerId = -1;
                        // ReSharper disable PossibleNullReferenceException
                        m_currentImageName = tag["Name"].InnerText;
                        m_currentImageTitle = tag["Title"].InnerText;
                        // ReSharper restore PossibleNullReferenceException
                        GetMap(server, m_currentImageName);
                        GetLegend(tag);
                        ApplySettings();
                    }
            }

        }

        private void ApplySettings()
        {
            if (File.Exists(MapFileName(m_currentImageName)))
            {
                if (Settings.Default.UseBaseMap)
                {
                    Wallpaper.Set(MapFileName(m_currentImageName), m_currentImageTitle, Wallpaper.Style.Stretched,
                                  BackgroundFile);
                }
                else
                {
                    Wallpaper.Set(MapFileName(m_currentImageName), m_currentImageTitle, Wallpaper.Style.Stretched);
                }

                if (!string.IsNullOrEmpty(m_currentImageTitle))
                    notifyIcon1.Text = m_currentImageTitle.Substring(0, Math.Min(63, m_currentImageTitle.Length));

                // Reset every time we change the picture.
                timer1.Stop();
                timer1.Start();
            }
        }

        private void notifyIcon1_MouseClick(object sender, MouseEventArgs e)
        {
        }

        private void timer1_Tick(object sender, EventArgs e)
        {
            try
            {
                RandomNewPicture();
            }
            catch(Exception exception)
            {
                eventLog1.WriteEntry(exception.Message);                
            }
        }

        private void contextMenuStrip1_Opening(object sender, System.ComponentModel.CancelEventArgs e)
        {
            foreach (ToolStripItem item in this.transparencyToolStripMenuItem.DropDown.Items)
            {
                if (item is ToolStripMenuItem)
                    ((ToolStripMenuItem)item).Checked = (Settings.Default.Transparency.ToString() == item.Text);
            }

            foreach (ToolStripItem item in this.refreshPeriodToolStripMenuItem.DropDown.Items)
            {
                
                if (item is ToolStripMenuItem)
                    ((ToolStripMenuItem)item).Checked = (Settings.Default.Period.Minutes.ToString() == item.Text);
            }
        }

        private void contextMenuStrip1_ItemClicked(object sender, ToolStripItemClickedEventArgs e)
        {
            
        }

        private void useBackground_Click(object sender, EventArgs e)
        {
            Settings.Default.UseBaseMap = (!Settings.Default.UseBaseMap);

            useBackground.Checked = Settings.Default.UseBaseMap;
        }

        void DefaultPropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
        {
            Settings.Default.Save();
            ApplySettings();
        }

        private void toolStripPeriod_Click(object sender, EventArgs e)
        {
            Settings.Default.Period = new TimeSpan(0, Int32.Parse(((ToolStripMenuItem) sender).Text), 0);
        }

        private void toolStripTransparency_Click(object sender, EventArgs e)
        {
            Settings.Default.Transparency = float.Parse(((ToolStripMenuItem)sender).Text);
        }

        private void Form1_Load(object sender, EventArgs e)
        {
        }

        private void exitToolStripMenuItem_Click(object sender, EventArgs e)
        {
            Application.Exit();
        }

    }
}
